package com.irdstudio.apicenter.frame.maker.engine.velocity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.Validate;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.runtime.RuntimeConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.irdstudio.apicenter.console.startup.MacmsRoot;
import com.irdstudio.apicenter.frame.core.jdbc.container.DataList;
import com.irdstudio.apicenter.frame.core.jdbc.container.DataRow;
import com.irdstudio.apicenter.frame.maker.dm.SPageParamTag;
import com.irdstudio.apicenter.frame.maker.engine.ICodeGenerator;
import com.irdstudio.apicenter.frame.util.PathUtil;

/**
 * 使用velocity生成代码文件
 * 
 * @author zs.ligm
 * @version 1.0
 * @date 2015-08-13
 */
public class VelocityCodeGenerator implements ICodeGenerator {

	protected final static Logger logger = LoggerFactory
			.getLogger(VelocityCodeGenerator.class);

	// 初始化Velocity
	static {
		try {
			String veloctiyInitFile = "velocityParams.properties";
			logger.info("init velocity with " + veloctiyInitFile + "...");
			PropertiesConfiguration configuration = new PropertiesConfiguration(
					veloctiyInitFile);
			Properties velocityProperties = new Properties();

			Iterator<String> keys = configuration.getKeys();
			while (keys.hasNext()) {
				String key = keys.next();
				String value = configuration.getString(key);
				velocityProperties.setProperty(key, value);
				logger.info("key = " + key + " value = " + value);
			}

			// 设置模板路径为工程根目录下
			String webRootPath = PathUtil.getProjectRootPath() + "template/vm";
			velocityProperties.setProperty(
					RuntimeConstants.FILE_RESOURCE_LOADER_PATH, webRootPath);
			logger
					.info("key = "
							+ RuntimeConstants.FILE_RESOURCE_LOADER_PATH
							+ " value = "
							+ velocityProperties
									.getProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH));

			// 单实例Velocity初始化并启动
			Velocity.init(velocityProperties);

		} catch (ConfigurationException e) {
			logger.error("velocityParams.properties init error : ", e);
		}
	}

	@Override
	public File generate(String templateFile, DataList paramDataList,
			String targetFile, Map<String, List<SPageParamTag>> tagGridMap, String[] module) throws IOException {
		String[] fileArray = templateFile.split(",");
		Validate.notEmpty(fileArray[0], "模板文件为空,请指定模板文件!");

		File tf = new File(Velocity
				.getProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH)
				+ "/" + fileArray[0]);
		logger
				.info("模板文件"
						+ Velocity
								.getProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH)
						+ "/" + fileArray[0]);
		if (!tf.exists()) {
			logger
					.info("模板文件"
							+ Velocity
									.getProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH)
							+ "/" + fileArray[0] + "不存在!");
			return null;
		}
		Validate.notNull(targetFile, targetFile + " not found.");

		// 根据模板文件生成目标文件
		Template template = Velocity.getTemplate(fileArray[0]);

		// 将模板参数转换为velocity能识别的上下文参数
		VelocityContext context = getVelocityContextFromParam(paramDataList, tagGridMap);

		// 将模板参数与模板合并以生成文件
		StringWriter writer = new StringWriter();
		template.merge(context, writer);
		System.out.println("生成代码结果："+writer.toString());
		return writeToFile(fileArray[1], writer.toString(), module, fileArray[0].substring(0, fileArray[0].lastIndexOf(".")));
	}

	/**
	 * 将模板所需要的参数转换为veloctiy能识别的上下文参数
	 * 
	 * @param paramDataList
	 * @return
	 */
	private VelocityContext getVelocityContextFromParam(DataList paramDataList, Map<String, List<SPageParamTag>> tagGridMap) {
		VelocityContext context = new VelocityContext();
		for (int i = 0; i < paramDataList.size(); i++) {
			DataRow row = paramDataList.get(i);
			System.out.println(row.getValue("template_param_code")+"->"+row.getValue("param_value"));
			if(!"02".equals(row.getValue("template_param_type"))){
				context.put(row.getValue("template_param_code"),
						row.getValue("param_value"));
			}
			/*if(row.containKey("tag_value_src")){
				context.put(row.getValue("tag_name"),
						row.getValue("tag_value_src"));
				System.out.println(row.getValue("tag_name")+"->"+row.getValue("tag_value_src"));
			}*/
		}
		if(tagGridMap != null){
			Iterator<Map.Entry<String, List<SPageParamTag>>> iter = tagGridMap.entrySet().iterator();
			while(iter.hasNext()){
				Map.Entry<String, List<SPageParamTag>> entry = iter.next();
				context.put(entry.getKey(), entry.getValue());
			}
		}
		//context.put("name", "ligm");
		//context.put("title", "移动审批系统");
		return context;
	}
	
	public File writeToFile(String type, String message, String[] module, String tempName) throws IOException {
		// 判断工程目录是否存在,如果不存在,则从SVN下更新代码
		String filepath = MacmsRoot.getMacmsPathService()
			.getMacmsWorkspacePath().concat("/appprj/").concat(module[0]).concat("/");
		System.out.println("文件名称===="+tempName+"======文件类型=="+type);
		String filetype = "text";
		if("01".equals(type)){
			filetype = "html";
		}else if("02".equals(type)){
			filetype = "js";
		}else if("03".equals(type)){
			filetype = "jsp";
		}else if("04".equals(type)){
			filetype = "java";
		}
		String modulePath = filepath + "module/" + module[1];
		String path = modulePath + "/" + module[2]+ tempName + "." + filetype;
		File descFile = new File(path);
		File flod = new File(modulePath);
		if (!flod.exists()) {
			flod.mkdirs();
		}
		if (descFile.exists()) {
			FileWriter fw =  new FileWriter(descFile);
			fw.write("");
			fw.close();
		}else{
			descFile.createNewFile();
		}
		FileOutputStream fout = new FileOutputStream(descFile.getPath(), true);
		byte[] bytes = message.getBytes();
		fout.write(bytes);
		fout.flush();
		fout.close();
		//在svn版本库中创建目录
		MacmsRoot.getSvnProjectService().createSvnDirect(module[0], module[0]+"/module/" + module[1]);
		return descFile;
	}
	
}
